package model

import (
	"bufio"
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"gorm.io/gorm"
	"net/http"
	"strings"
	"time"
)

type ChatMessages struct {
	Id        uint      `gorm:"column:id;type:bigint UNSIGNED;comment:主键ID;primaryKey;not null;" json:"id"`           // 主键ID
	SessionId uint      `gorm:"column:session_id;type:bigint;comment:关联会话Id;not null;" json:"session_id"`             // 关联会话Id
	Role      string    `gorm:"column:role;type:varchar(10);comment:消息角色 user=用户 assistant=AI;not null;" json:"role"` // 消息角色 user=用户 assistant=AI
	Content   string    `gorm:"column:content;type:text;comment:消息内容;not null;" json:"content"`                       // 消息内容
	CreatedAt time.Time `gorm:"column:created_at;type:datetime(3);not null;default:CURRENT_TIMESTAMP(3);" json:"created_at"`
}

func (cm *ChatMessages) TableName() string {
	return "chat_messages"
}

// 1. 保存一对消息（user + assistant）
// 参数、返回值保持与原 dao.SavePair 完全一致
func SavePair(ctx context.Context, db *gorm.DB, sid uint64, user, ai string) error {
	msgs := []ChatMessages{
		{SessionId: uint(sid), Role: "user", Content: user, CreatedAt: time.Now()},
		{SessionId: uint(sid), Role: "assistant", Content: ai, CreatedAt: time.Now()},
	}
	return db.WithContext(ctx).Create(&msgs).Error
}

// 2. 查询某会话全部历史
// 参数、返回值保持与原 dao.List 完全一致
func List(ctx context.Context, db *gorm.DB, sid uint64) ([]ChatMessages, error) {
	var msgs []ChatMessages
	err := db.WithContext(ctx).
		Where("session_id = ?", sid).
		Order("created_at ASC").
		Find(&msgs).Error
	return msgs, err
}

// 3. 调用 AI（带历史）
// 参数、返回值保持与原 dao.Talk 完全一致
// 额外把 config 参数透传进来（dao 会把 dao.c 透传）

func Talk(
	ctx context.Context,
	db *gorm.DB,
	conf struct {
		TongYi struct {
			Url, Model, ApiKey string
		}
	},
	sid uint64,
	userInput string,
) (string, error) {

	// 1. 拉历史
	hist, err := List(ctx, db, sid)
	if err != nil {
		return "", err
	}

	// 2. 拼 messages
	msgs := make([]map[string]string, 0, len(hist)+1)
	for _, m := range hist {
		msgs = append(msgs, map[string]string{"role": m.Role, "content": m.Content})
	}
	msgs = append(msgs, map[string]string{"role": "user", "content": userInput})

	// 3. 请求体（OpenAI 兼容格式）
	body, _ := json.Marshal(map[string]interface{}{
		"model":    conf.TongYi.Model, // 例如 qwen-turbo
		"messages": msgs,
		"stream":   true,
		// 通义增量输出开关（只在流式时生效）
		"incremental_output": true,
	})

	// 4. 发请求
	req, _ := http.NewRequest(http.MethodPost,
		conf.TongYi.Url,
		bytes.NewReader(body))
	req.Header.Set("Authorization", "Bearer "+conf.TongYi.ApiKey)
	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()

	// 5. 降级：非流式（保险）
	if !strings.Contains(resp.Header.Get("Content-Type"), "text/event-stream") {
		var r struct {
			Choices []struct {
				Message struct {
					Content string `json:"content"`
				} `json:"message"`
			} `json:"choices"`
		}
		if err = json.NewDecoder(resp.Body).Decode(&r); err != nil {
			return "", err
		}
		if len(r.Choices) == 0 {
			return "", fmt.Errorf("empty response")
		}
		return strings.TrimSpace(r.Choices[0].Message.Content), nil
	}

	// 6. 逐行 SSE 解析
	var builder strings.Builder
	scanner := bufio.NewScanner(resp.Body)
	for scanner.Scan() {
		line := scanner.Text()
		if !strings.HasPrefix(line, "data: ") {
			continue
		}
		data := strings.TrimPrefix(line, "data: ")
		if data == "[DONE]" {
			break
		}
		var chunk struct {
			Choices []struct {
				Delta struct {
					Content string `json:"content"`
				} `json:"delta"`
			} `json:"choices"`
		}
		if err = json.Unmarshal([]byte(data), &chunk); err != nil {
			continue
		}
		if len(chunk.Choices) > 0 {
			txt := chunk.Choices[0].Delta.Content
			builder.WriteString(txt)
			// TODO: 把 txt 实时推给前端（WebSocket / SSE）
			fmt.Print(txt) // 调试用
		}
	}
	if err = scanner.Err(); err != nil {
		return "", err
	}

	final := strings.TrimSpace(builder.String())
	if final == "" {
		return "抱歉，我暂时无法回答这个问题，换个说法试试吧！", nil
	}
	return final, nil
}
